home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 399_01 / mined1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-03  |  47.9 KB  |  2,078 lines

  1. /*  ==================================================================    *
  2.  *                Editor mined                *
  3.  *                Part 1                    *
  4.  *            for documentation see mined.doc            *
  5.  *  ==================================================================    */
  6.  
  7. #include "mined.h"
  8.  
  9. /* #define DEBUG */
  10.  
  11. /*  ==================================================================    *
  12.  *            Definitions specific for mined1.c        *
  13.  *  ==================================================================    */
  14.  
  15. #ifndef helpcommand
  16.  
  17. # ifdef unix
  18. # define helpcommand "man mined"
  19. # endif
  20.  
  21. # ifdef vms
  22. # define helpcommand "help mined"
  23. # endif
  24.  
  25. # ifdef msdos
  26. # define helpcommand "more < %smined.hlp"
  27. # endif
  28.  
  29. #endif
  30.  
  31. #ifndef printcommand
  32.  
  33. # ifdef unix
  34. #  ifdef sysV
  35. #  define printcommand "lp %s"
  36. #  else
  37. #  define printcommand "lpr %s"
  38. #  endif
  39. # endif
  40.  
  41. # ifdef vms
  42. # define printcommand "print %s"
  43. # endif
  44.  
  45. # ifdef msdos
  46. # define printcommand "copy %s prn: > nul:"
  47. # endif
  48.  
  49. #endif
  50.  
  51. /*  ==================================================================    *
  52.  *                Data section                *
  53.  *  ==================================================================    */
  54.  
  55. LINE * header;            /* Head of line list */
  56. LINE * tail;            /* Last line in line list */
  57. LINE * cur_line;        /* Current line in use */
  58. LINE * top_line;        /* First line of screen */
  59. LINE * bot_line;        /* Last line of screen */
  60. char * cur_text;        /* Current char on current line in use */
  61. int last_y;            /* Last y of screen. Usually SCREENMAX */
  62. int x = 0, y = 0;        /* x, y coordinates on screen */
  63.  
  64. short YMAX, XMAX;
  65. char screen [screen_BUFL + 1];    /* I/O buffer for "writes" and "reads" */
  66. int total_lines = 0;        /* Number of lines in file */
  67. long total_chars = -1L;        /* Number of characters in file */
  68. FLAG modified = FALSE;        /* Set when file is modified */
  69. FLAG viewonly = FALSE;        /* Set when view only mode is selected */
  70. FLAG overwriteOK = FALSE;    /* Set if current file is OK for overwrite */
  71. FLAG writable;            /* Set if file cannot be written */
  72. FLAG loading = TRUE;        /* Loading a file? Init TRUE for error handling */
  73. FLAG quit = FALSE;        /* Set when quit character is typed */
  74. FLAG intr_char = FALSE;        /* Set when intr character is typed */
  75. FLAG winchg = FALSE;        /* Set when window size has changed */
  76. FLAG isscreenmode = FALSE;    /* Set when screen mode is on */
  77. FLAG stat_visible;        /* Set if status_line is visible */
  78. FLAG fstat_always = FALSE;    /* Permanent file status display wanted ? */
  79. FLAG waitingforinput = FALSE;    /* Set while waiting for the next command key */
  80. FLAG rpipe = FALSE;        /* Set if file should be read from stdin */
  81. FLAG wpipe = FALSE;        /* Set if file should be written to stdout */
  82. FLAG multiexit = TRUE;        /* Should exit command go to next file? */
  83. FLAG proportional = FALSE;    /* Enable support for proportional fonts? */
  84. FLAG controlQS = FALSE;        /* must respect ^Q/^S handshake ? */
  85. FLAG insert_mode = TRUE;    /* insert or overwrite */
  86. uchar control_prefix = '\026';    /* ^V/^P character to prefix control chars */
  87. FLAG Chinese = FALSE;        /* set if two-byte characters are enabled */
  88. FLAG page_scroll = FALSE;    /* use scroll for page up/down */
  89. FLAG page_stay = FALSE;        /* stay at edge of screen after page up/down */
  90. #ifdef pc
  91. int display_delay = 9;        /* delay between display lines */
  92. #else
  93. int display_delay = -1;        /* Unix terminals are slow enough anyway */
  94. #endif
  95. #ifdef msdos
  96. char RET_opt = 'r';        /* handle RET chars: ignore / newline */
  97. #else
  98. char RET_opt = ' ';        /* handle RET chars: ignore / newline */
  99. #endif
  100. long chars_saved;        /* Nr of chars in buffer */
  101. int input_fd = STD_IN;        /* File descriptors for terminal dialog */
  102. int output_fd = STD_ERR;
  103. int out_count = 0;        /* Index in output buffer */
  104. char file_name [maxLINE_LEN];    /* Name of file in use */
  105. char text_buffer [MAX_CHARS];    /* for get_line, modifications, build_string */
  106. int hop_flag = 0;        /* Counter for the HOP function */
  107. char TABchar = ' ';        /* Char to be shown in place of tab chars */
  108. char SHIFT_BEG = '\0';        /* Char indicating that line continues left */
  109. char RET_MARK = '\0';        /* Char indicating end of line */
  110. char RET_BLANK = '\0';        /* Char to fill the end of line with */
  111. char RET_BLANK2 = '\0';        /* Char to fill last position of line with */
  112. #ifdef vms
  113. int fprot = 0;            /* To be used for file creatings */
  114. int bufprot = 0;        /* To be used for paste buffer file */
  115. #else
  116. int fprot = 0644;        /* To be used for file creatings */
  117. int bufprot = 0600;        /* To be used for paste buffer file */
  118. #endif
  119. int fnami;            /* Parameter index of current file name */
  120. int fnami_min, fnami_max, fnami_cnt;
  121. /* char * (* fnamv) []; */
  122. char * * fnamv;            /* Copy of argv. Points to program params */
  123.  
  124. int left_margin = 0;
  125. int right_margin = 71;
  126.  
  127. /*
  128.  * Yank variables.
  129.  */
  130. char * temp_dir;
  131. char yank_file [maxLINE_LEN];
  132. char yankie_file [maxLINE_LEN];
  133. char panic_file [maxLINE_LEN];
  134. char mined_dir [maxLINE_LEN];    /* startup directory to locate help file */
  135.  
  136. /*  ==================================================================    *
  137.  *            Text buffer routines                *
  138.  *  ==================================================================    */
  139.  
  140. int old_x = 0;    /* previous x position */
  141.  
  142. /*
  143.  * Find_x () returns the x coordinate belonging to address.
  144.  * (Tabs are expanded).
  145.  */
  146. int
  147. find_x (line, address)
  148.   LINE * line;
  149.   char * address;
  150. {
  151.   register char * textp = line->text;
  152.   register int x_left = get_shift (line->shift_count) * - SHIFT_SIZE;
  153.   register int x_in_line = 0;    /* must start from 0 to calculate correct 
  154.             tab positions (since SHIFT_SIZE is not guaranteed 
  155.             to be a multiple of 8) */
  156.     /* Alright, SHIFT_SIZE is now guaranteed to be a multiple of 8 
  157.        due to lots of display problems related to that matter.
  158.        Leave this code anyway. */
  159.  
  160.   while (textp != address && * textp != '\0') {
  161.     if (is_tab (* textp ++))    /* Expand tabs */
  162.         x_in_line = tab (x_in_line);
  163.     else
  164.         x_in_line ++;
  165.   }
  166.   return x_in_line + x_left;
  167. }
  168.  
  169. /*
  170.  * Find_address () returns the pointer in the line with given offset.
  171.  * (Tabs are expanded).
  172.  * find_address is only called by move_it ()
  173. get_shift (cnt)        is    ((cnt) & DUMMY_MASK) ; DUMMY_MASK is 0x7F
  174. tab (cnt)        is    (((cnt) + 8) & ~07)
  175. is_tab (c)        is    ((c) == '\t')
  176.  */
  177. char *
  178. find_address (line, new_x, cur_x)
  179.   LINE * line;
  180.   int new_x;
  181.   int * cur_x;
  182. {
  183.   register char * textp = line->text;
  184.   register int tx = get_shift (line->shift_count) * - SHIFT_SIZE;
  185.  
  186.   while (tx < new_x && * textp != '\n') {
  187.     if (is_tab (* textp)) {
  188.         if (new_x == old_x /* (* cur_x) */ - 1 && tab (tx) > new_x)
  189.             break;    /* Moving left over tab */
  190.         else
  191.             tx = tab (tx);
  192.     }
  193.     else    tx ++;
  194.     textp ++;
  195.   }
  196.   * cur_x = tx;
  197.   return textp;
  198. }
  199.  
  200. /*
  201.  * inmultichar (string, charpoi) determines if charpoi points to the second 
  202.  * byte of a multi-byte character within string
  203.  */
  204. int
  205. inmultichar (string, charpoi)
  206.   uchar * string;
  207.   uchar * charpoi;
  208. {
  209.   while (string < charpoi) {
  210.     if (multichar (* string)) {
  211.         string ++;
  212.         if (* string != '\n' /* would be an error */) string ++;
  213.     } else
  214.         string ++;
  215.   }
  216.   return string > charpoi;
  217. }
  218.  
  219. /*
  220.  * move_to: move to given coordinates on screen.
  221.  * move_y: move to given line on screen, staying in last explicit column.
  222.  * move_address: move to given line at given text position.
  223.  * The caller must check that scrolling is not needed.
  224.  * If new x-position is < 0 or > XBREAK, move_it () will check if
  225.  * the line can be shifted. If it can it sets (or resets) the shift_count
  226.  * field of the current line accordingly. By this mechanism, the
  227.  * pseudo-x-positions LINE_START / LINE_END (a very small / big value)
  228.  * perform the appropriate positioning actions.
  229.  * Move also sets cur_text to the right char.
  230.  * "If we're moving to the same x coordinate, try to move the the x-coordinate
  231.  * used on the other previous call." -- This worked erroneously and was 
  232.  * replaced by an explicit old_x variable and move_y call.
  233.  * move_address is directly called by move_next/previous_word(), re_search(), RDwin()
  234.  */
  235. void
  236. move_it (new_x, new_address, new_y)
  237.   register int new_x;
  238.   int new_y;
  239.   char * new_address;
  240. {
  241.   register LINE * line = cur_line;    /* For building new cur_line */
  242.   int shift = 0;            /* How many shifts to make */
  243. /*  static int rel_x = 0;    */    /* Remember relative x position */
  244. /*    This was used as a trick to stay virtually in the previous column 
  245.     even when moving across shorter lines; but it had >= 2 errors.
  246.     Renamed to old_x, made globally accessible and explicitly used 
  247.     by appropriate calls to avoid these problems. TW */
  248.   int tx = x;
  249.  
  250. /* Check for illegal values */
  251.   if (new_y < 0 || new_y > last_y)
  252.     return;
  253.  
  254. /* Adjust y-coordinate and cur_line */
  255.   if (new_y < y)
  256.     while (y != new_y) {
  257.         y --;
  258.         line = line->prev;
  259.     }
  260.   else
  261.     while (y != new_y) {
  262.         y ++;
  263.         line = line->next;
  264.     }
  265.  
  266. /* Set or unset relative x-coordinate */
  267.   if (new_address == NIL_PTR) {
  268.     new_address = find_address (line, new_x, & tx);
  269.     new_x = tx;
  270.   }
  271.   else
  272.     /* rel_x = */ new_x = find_x (line, new_address);
  273.  
  274. /* Adjust on character boundary */
  275.   if (Chinese == TRUE) {
  276.     if (inmultichar (line->text, new_address)) {
  277.     /* adjust position which is currently within a multi-byte character */
  278.         if (new_x >= x) {
  279.             new_x ++;
  280.             new_address ++;
  281.         } else {
  282.             new_x --;
  283.             new_address --;
  284.         }
  285.     }
  286.   }
  287.  
  288. /* Adjust shift_count if new_x lower than 0 or higher than XBREAK */
  289. /* Allow adjustment also if new_x == 0 to enable left shift mark */
  290.   if (new_x <= 0 || new_x >= XBREAK) {
  291.     if (new_x > XBREAK || (new_x == XBREAK && * new_address != '\n'))
  292.         shift = (new_x - XBREAK) / SHIFT_SIZE + 1;
  293.     else {
  294.         shift = new_x / SHIFT_SIZE;
  295.         if (new_x % SHIFT_SIZE)
  296.             shift --;
  297.         if (new_x == 0 && line->shift_count != 0 && SHIFT_BEG != '\0')
  298.             shift --;
  299.     }
  300.  
  301.     if (shift != 0) {
  302.         line->shift_count += shift;
  303.         new_x = find_x (line, new_address);
  304.         if (new_x == 0 && line->shift_count != 0 && SHIFT_BEG != '\0')
  305.         {    line->shift_count --;
  306.             new_x = find_x (line, new_address);
  307.         }
  308.         set_cursor (0, y);
  309.         line_print (line);
  310.         /* rel_x = new_x; */
  311.     }
  312.   }
  313.  
  314. /* Assign and position cursor */
  315.   x = new_x;
  316.   cur_text = new_address;
  317.   cur_line = line;
  318.   set_cursor_xy ();
  319. }
  320.  
  321. void
  322. move_y (ny)
  323.   register int ny;
  324. {
  325.   move_it (old_x, NIL_PTR, ny);
  326. }
  327.  
  328. void
  329. move_to (nx, ny)
  330.   register int nx;
  331.   register int ny;
  332. {
  333.   old_x = x;
  334.   move_it (nx, NIL_PTR, ny);
  335.   old_x = x;
  336. }
  337.  
  338. void
  339. move_address (nadd, ny)
  340.   register char * nadd;
  341.   register int ny;
  342. {
  343.   old_x = x;
  344.   move_it (0, nadd, ny);
  345.   old_x = x;
  346. }
  347.  
  348. /*
  349.  * Initialize is called when a another file is edited. It free's the allocated 
  350.  * space and sets modified back to FALSE and fixes the header/tail pointer.
  351.  */
  352. void
  353. initialize ()
  354. {
  355.   register LINE * line, * next_line;
  356.  
  357. /* Delete the whole list */
  358.   for (line = header->next; line != tail; line = next_line) {
  359.     next_line = line->next;
  360.     free_space (line->text);
  361.     free_header (line);
  362.   }
  363.  
  364. /* header and tail should point to itself */
  365.   line->next = line->prev = line;
  366.   x = y = 0;
  367.   rpipe = modified = FALSE;
  368. }
  369.  
  370. /*
  371.  * Get_line reads one line from filedescriptor fd. If EOF is reached on fd,
  372.  * get_line () returns ERRORS, else it returns the length of the string.
  373.  */
  374. char * get_l_err1;
  375. char * get_l_err2;
  376. char last_char = '\0';
  377.  
  378. int
  379. get_line (fd, buffer)
  380.   int fd;
  381.   register char buffer [MAX_CHARS];
  382. {
  383.   static char * last = NIL_PTR;
  384.   static char * current = NIL_PTR;
  385.   static int read_chars;
  386.   register char * cur_pos = current;
  387.   char * begin = buffer;
  388.   char * fini = buffer + MAX_CHARS - 2 /* leave space for '\n\0' */;
  389.   register FLAG ignore1char;
  390.  
  391.   do {
  392.     do {
  393.         ignore1char = FALSE;
  394.         if (cur_pos == last) {
  395.         if ((read_chars = read (fd, screen, screen_BUFL)) <= 0)
  396.             break;
  397.         last = & screen [read_chars];
  398.         cur_pos = screen;
  399.         }
  400.  
  401.         if (* cur_pos == '\0' ) {
  402.         get_l_err1 = "File contains NULL char's - changed to DEL's -   ";
  403.         * cur_pos = '\177';
  404.         }
  405.  
  406. #ifdef msdos
  407.         if (* cur_pos == '\n' && last_char != '\r')
  408.         modified = TRUE;
  409. #endif
  410.         if (RET_opt == 'R' && * cur_pos == '\n' && last_char == '\r') {
  411.         last_char = * cur_pos;
  412.         cur_pos ++;
  413.         ignore1char = TRUE;
  414.         modified = TRUE;
  415.         }
  416.         else
  417.         last_char = * cur_pos;
  418.  
  419.         if (* cur_pos == '\r' ) {
  420.         if (RET_opt == 'R') {
  421.             * cur_pos = '\n';
  422.             modified = TRUE;
  423.         }
  424.         else if (RET_opt == 'r') {
  425.             cur_pos ++;
  426.             ignore1char = TRUE;
  427. #ifndef msdos
  428.             modified = TRUE;
  429. #endif
  430.         }
  431.         }
  432.     } while (ignore1char == TRUE);
  433.     if (cur_pos == last) break;
  434.     if (buffer == fini && * cur_pos != '\n') {
  435.         get_l_err2 = "Line too long - split";
  436.         * buffer ++ = '\n';
  437.         break;
  438.     }
  439.   } while ((* buffer ++ = * cur_pos ++) != '\n');
  440.  
  441.   current = cur_pos;
  442.   if (read_chars <= 0) {
  443.     if (buffer == begin)
  444.         return ERRORS;
  445.     if (* (buffer - 1) != '\n')
  446.         if (loading == TRUE) /* Add '\n' to last line of file */
  447.             * buffer ++ = '\n';
  448.         else {
  449.             * buffer = '\0';
  450.             return NO_LINE;
  451.         }
  452.   }
  453.  
  454.   * buffer = '\0';
  455.   return (int) (buffer - begin);
  456. }
  457.  
  458. /*
  459.  * Load_file loads the file with given name or the input pipe into memory.
  460.  * If the file couldn't be opened, just an empty line is installed.
  461.  * Buffer pointers are initialized.
  462.  */
  463. void
  464. load_file_w_o_display (file)
  465.   char * file;
  466. {
  467.   register LINE * line = header;
  468.   register int len;
  469.   long nr_of_chars = 0L;
  470.   int fd = -1;            /* Filedescriptor for file */
  471.  
  472.   total_lines = 0;            /* Zero lines to start with */
  473.  
  474.   overwriteOK = FALSE;
  475. /* Open file */
  476.   writable = TRUE;        /* Benefit of the doubt */
  477.   if (file == NIL_PTR) {
  478.     if (rpipe == FALSE)
  479.         status_msg ("No file");
  480.     else {
  481.         fd = 0;
  482.         file = "standard input";
  483.     }
  484.     file_name [0] = '\0';
  485.   }
  486.   else {
  487.     copy_string (file_name, file);    /* Save file name */
  488.     if (access (file, 0 /* F_OK */) < 0) {    /* Cannot access file */
  489.         status_line ("New file ", file);
  490.         overwriteOK = TRUE;
  491.     }
  492.     else if ((fd = open (file, O_RDWR | O_BINARY, 0)) >= 0) {
  493.         overwriteOK = TRUE;
  494.         writable = TRUE;
  495.     }
  496.     else if ((fd = open (file, O_RDONLY | O_BINARY, 0)) < 0)
  497.         error ("Cannot open: " /*, file */, serror ());
  498.     else {    overwriteOK = TRUE;
  499.         writable = FALSE;
  500.     }
  501.   }
  502.  
  503. /* Read file */
  504.   loading = TRUE;        /* Loading file, so set flag */
  505.   get_l_err1 = NIL_PTR;
  506.   get_l_err2 = NIL_PTR;
  507.  
  508.   if (fd >= 0) {
  509.     status_line ("Reading ", file);
  510.     while (line != NIL_LINE
  511.         && (len = get_line (fd, text_buffer)) != ERRORS) {
  512.         line = line_insert (line, text_buffer, len);
  513.         nr_of_chars += (long) len;
  514.     }
  515.     if (total_lines == 0 && line != NIL_LINE)   /* The file was empty! */
  516.         line = line_insert (line, "\n", 1);
  517.     clear_buffer (); /* Clear output buffer: out_count = 0; */
  518.     cur_line = header->next;
  519.     (void) close (fd);        /* Close file */
  520.     if (line != NIL_LINE) {
  521.        if (get_l_err1 != NIL_PTR || get_l_err2 != NIL_PTR) {
  522.         ring_bell ();
  523.         error (get_l_err1, get_l_err2);
  524.         sleep (1);
  525.        }
  526.        fstatus ("Read", nr_of_chars);
  527.     }
  528.   }
  529.   else                /* Just install a "\n" */
  530.     line = line_insert (line, "\n", 1);
  531.  
  532.   if (line == NIL_LINE) {
  533.     sleep (2) /* give time to read allocation error msg */;
  534.     viewonly = TRUE;
  535.   }
  536.  
  537.   reset (header->next, 0);    /* Initialize pointers */
  538.   move_to (0, 0);
  539.   loading = FALSE;        /* Stop loading, reset flag */
  540. }
  541.  
  542. void
  543. load_file (file)
  544.   char * file;
  545. {
  546.   load_file_w_o_display (file);
  547. /* Print screen */
  548.   display (0, header->next, last_y, 0);
  549.   move_to (0, 0);
  550. /* fstatus ("Read", -1L); */
  551. }
  552.  
  553. /*-------------------------------------------------------------------------*/
  554.  
  555. /*
  556.  * Ask the user if he wants to save the file or not.
  557.  */
  558. int
  559. ask_save ()
  560. {
  561.   register uchar c;
  562.  
  563.   status_line (file_name [0] ? file_name : "[buffer]" ,
  564.             " has been modified. Save? (y/n)");
  565.     /* previously only basename (file_name) was printed */
  566.   c = promptyn ();
  567.   clear_status ();
  568.   if (c == 'y')
  569.     return wrt_text (TRUE);
  570.   else if (c == 'n')
  571.     return FINE;
  572.   else {
  573.     quit = FALSE;    /* abort character has been given */
  574.     return ERRORS;
  575.   }
  576. }
  577.  
  578. /*
  579.  * Ask user if named file should be overwritten.
  580.  */
  581. FLAG
  582. checkoverwrite (name)
  583. char * name;
  584. {
  585.   uchar c;
  586.  
  587.   if (access (name, 0 /* F_OK */) < 0)    /* Cannot access file */
  588.     return TRUE;    /* thus no danger of unwanted damage */
  589.  
  590.   status_line (name [0] ? name : "[buffer]" ,
  591.             ": OK to overwrite? (y/n)");
  592.     /* previously only basename (name) was printed */
  593.   c = promptyn ();
  594.   clear_status ();
  595.   if (c == 'y')
  596.     return TRUE;
  597.   else if (c == 'n')
  598.     return FALSE;
  599.   else {
  600. /*    quit = FALSE;    abort character has been given */
  601.     return FALSE;
  602.   }
  603. }
  604.  
  605. /*
  606.  * Attach new file name to buffer
  607.  */
  608. void
  609. NN ()
  610. {
  611.   char file [maxLINE_LEN];    /* Buffer for new file name */
  612.   if (get_file ("Enter new file name:", file) == ERRORS)
  613.     return;
  614.  
  615.   overwriteOK = FALSE;
  616.   writable = TRUE;
  617.   modified = TRUE;    /* cf. CHDI command */
  618.   copy_string (file_name, file);    /* Save new file name */
  619.   clear_status ();
  620. }
  621.  
  622. /*
  623.  * Write file in core to disc.
  624.  */
  625. /* Call graph for writing functions:
  626.     panic --\
  627.          > QUED --\
  628.     ESC q --/       > ask_save --\
  629.     ESC e ---> EDIT --/         \
  630.     ESC v ---> VIEW -/          \
  631.     ESC w -----------------------------> WT
  632.     ESC z -----------> SUSP ----------/
  633.     ESC ESC ---------> EXED ---------/
  634. */
  635. long write_count;    /* number of chars written */
  636. void
  637. write_file (fd)
  638.   int fd;
  639. {
  640.   register LINE * line;
  641.  
  642.   write_count = 0L;
  643.   clear_buffer (); /* out_count = 0; */
  644.   for (line = header->next; line != tail; line = line->next) {
  645.     if (line->shift_count & DUMMY) {
  646.         if (line->next == tail && line->text [0] == '\n')
  647.             continue;
  648.     }
  649.     if (writestring (fd, line->text) == ERRORS) {
  650.         write_count = -1L;
  651.         break;
  652.     }
  653.     write_count += (long) length_of (line->text);
  654.   }
  655.  
  656.   if (write_count > 0L && flush_buffer (fd) == ERRORS)
  657.     write_count = -1L;
  658.  
  659.   (void) close (fd);
  660. }
  661.  
  662. int
  663. wrt_text (conditional)
  664.   FLAG conditional;
  665. {
  666.   char file [maxLINE_LEN];    /* Buffer for new file name */
  667.   int fd;            /* Filedescriptor of file */
  668.   int ret;
  669.  
  670.   if (wpipe) {
  671.     fd = STD_OUT;
  672.     status_line ("Writing ", "to standard output");
  673.     wpipe = FALSE; /* no further write to same stream possible */
  674.   }
  675.   else {
  676.     if (modified == FALSE && viewonly == FALSE && conditional == TRUE) {
  677.     status_msg ("Write not necessary.");
  678.     return FINE;
  679.     }
  680.  
  681.     /* Check if file_name is valid and if file can be written */
  682.     if (file_name [0] == '\0' || writable == FALSE) {
  683.     overwriteOK = FALSE;
  684.     if ((ret = get_file ("Enter file name:", file)) != FINE)
  685.         return ret;
  686.     copy_string (file_name, file);        /* Save file name */
  687.     }
  688.     if (overwriteOK == FALSE) {
  689.     if (checkoverwrite (file_name) == TRUE)
  690.         overwriteOK = TRUE;
  691.     else {    if (quit == FALSE)
  692.             writable = FALSE;
  693.         return ERRORS;
  694.     }
  695.     }
  696.     if ((fd = creat (file_name, fprot)) < 0) {    /* Empty file */
  697.     error ("Cannot create or write: " /*, file_name */, serror ());
  698.     writable = FALSE;
  699.     return ERRORS;
  700.     }
  701.     else
  702.     writable = TRUE;
  703.  
  704.     status_line ("Writing ", file_name);
  705.   }
  706.  
  707.   write_file (fd);
  708.  
  709.   if (write_count == -1L)
  710.     return ERRORS;
  711.  
  712.   modified = FALSE;
  713.   rpipe = FALSE;    /* File name is now assigned */
  714.  
  715. /* Display how many chars (and lines) were written */
  716. /*  fstatus ("Wrote", write_count); */
  717.   fstatus ("Wrote", -1L);
  718.   return FINE;
  719. }
  720.  
  721. void
  722. WT ()
  723. {
  724.   (void) wrt_text (TRUE);
  725. }
  726.  
  727. void
  728. WTU ()
  729. {
  730.   (void) wrt_text (FALSE);
  731. }
  732.  
  733. int
  734. panicwrite ()
  735. {
  736.   int fd;
  737.   fd = creat (panic_file, fprot);
  738.   write_file (fd);
  739.   if (write_count == -1L)
  740.     return ERRORS;
  741.   else    return FINE;
  742. }
  743.  
  744. /*
  745.  * Edit/view another file. If the current file has been modified, 
  746.  * ask whether the user wants to save it.
  747.  * (We could allow to switch between edit and view mode without changing 
  748.  * the file, but we would have to consider carefully the relationship 
  749.  * between viewonly and modified.)
  750.  */
  751. void
  752. edit_file (prompt, vomode)
  753.   char * prompt;
  754.   FLAG vomode;
  755. {
  756.   char new_file [maxLINE_LEN];    /* Buffer to hold new file name */
  757.  
  758.   if (modified == TRUE && viewonly == FALSE && ask_save () != FINE)
  759.     return;
  760.  
  761.   viewonly = vomode;
  762.  
  763. /* Get new file name */
  764.   if (get_file (prompt, new_file) == ERRORS)
  765.     return;
  766.  
  767. /* Free old linked list, initialize global variables and load new file */
  768.   initialize ();
  769.   clear_screen ();
  770.   load_file (new_file [0] == '\0' ? NIL_PTR : new_file);
  771. }
  772.  
  773. void
  774. EDIT ()
  775. {
  776.   edit_file ("Edit file:", FALSE);
  777. }
  778.  
  779. void
  780. VIEW ()
  781. {
  782.   edit_file ("View file:", TRUE);
  783. }
  784.  
  785. void
  786. edit_nth_file (n)
  787.   int n;
  788. {
  789.   int number, index;
  790.  
  791.   if (modified == TRUE && viewonly == FALSE && ask_save () != FINE)
  792.     return;
  793.  
  794.   if (n == -1) {
  795.     index = get_number ("Edit which file (enter number) ...", '\0', & number);
  796.     if (index == ERRORS) return;
  797.     n = number - 1 + fnami_min;
  798.   }
  799.   if (n < fnami_min) n = fnami_min;
  800.   if (n > fnami_max) n = fnami_max;
  801.  
  802. /* Free old linked list, initialize global variables and load new file */
  803.   initialize ();
  804.   clear_screen ();
  805.  
  806.   fnami = n;
  807.   if (fnami < fnami_min) load_file (NIL_PTR);
  808. /*  else load_file ((* fnamv) [fnami]); */
  809.   else load_file (fnamv [fnami]);
  810. }
  811.  
  812. void
  813. NXTFILE ()
  814. {
  815.   if (hop_flag > 0) edit_nth_file (fnami_max);
  816.   else edit_nth_file (fnami + 1);
  817. }
  818.  
  819. void
  820. PRVFILE ()
  821. {
  822.   if (hop_flag > 0) edit_nth_file (fnami_min);
  823.   else edit_nth_file (fnami - 1);
  824. }
  825.  
  826. void
  827. NTHFILE ()
  828. {
  829.   edit_nth_file (-1);
  830. }
  831.  
  832. /*
  833.  * Leave editor. If the file has changed, ask if the user wants to save it.
  834.  */
  835. void
  836. QUED ()
  837. {
  838.   if (modified == TRUE && viewonly == FALSE && ask_save () != FINE)
  839.     return;
  840.  
  841.   delete_yank_file ();
  842.   set_cursor (0, YMAX);
  843.   putchar ('\n');
  844.   raw_mode (OFF);
  845.   exit (0);
  846. }
  847.  
  848. /*
  849.  * Exit editing current file. If the file has changed, save it.
  850.  * Edit next file if there is one.
  851.  */
  852. void
  853. EXFILE ()
  854. {
  855.   if (modified == TRUE)
  856.     if (wrt_text (TRUE) != FINE) return;
  857.  
  858.   if (fnami < fnami_max) NXTFILE ();
  859.   else {
  860.     delete_yank_file ();
  861.     set_cursor (0, YMAX);
  862.     putchar ('\n');
  863.     raw_mode (OFF);
  864.     exit (0);
  865.   }
  866. }
  867.  
  868. /*
  869.  * Exit editor. If the file has changed, save it.
  870.  */
  871. void
  872. EXMINED ()
  873. {
  874.     if (modified == TRUE)
  875.         if (wrt_text (TRUE) != FINE) return;
  876.  
  877.     delete_yank_file ();
  878.     set_cursor (0, YMAX);
  879.     putchar ('\n');
  880.     raw_mode (OFF);
  881.     exit (0);
  882. }
  883.  
  884. /*
  885.  * Exit editing current file. Exit editor if multiexit flag set.
  886.  */
  887. void
  888. EXED ()
  889. {
  890.   if (multiexit == TRUE) EXFILE ();
  891.   else EXMINED ();
  892. }
  893.  
  894. /*
  895.  * Count_chars () count the number of chars that the line would occupy on the
  896.  * screen. Counting starts at the real x-coordinate of the line.
  897.  * Was only called by delete_text ().
  898.  */
  899. #ifdef UNUSED
  900. int
  901. count_chars (line)
  902.   LINE * line;
  903. {
  904.   register int cnt = get_shift (line->shift_count) * - SHIFT_SIZE;
  905.   register char * textp = line->text;
  906.  
  907. /* Find begin of line on screen */
  908.   while (cnt < 0) {
  909.     if (is_tab (* textp ++))
  910.         cnt = tab (cnt);
  911.     else
  912.         cnt ++;
  913.   }
  914.  
  915. /* Count number of chars left */
  916.   cnt = 0;
  917.   while (* textp != '\n') {
  918.     if (is_tab (* textp ++))
  919.          cnt = tab (cnt);
  920.     else
  921.         cnt ++;
  922.   }
  923.   return cnt;
  924. }
  925. #endif /* UNUSED */
  926.  
  927. /*  ==================================================================    *
  928.  *                Line wrap around            *
  929.  *  ==================================================================    */
  930.  
  931. /*
  932.  * Advance pointer and counter to next character.
  933.  * Handle tab characters and Chinese 2-byte characters correctly.
  934.  */
  935. void
  936. advance_char (poipoi, colpoi)
  937.   char * * poipoi;
  938.   int * colpoi;
  939. {
  940.   if (is_tab (* * poipoi)) {
  941.     (* poipoi) ++;
  942.     * colpoi = tab (* colpoi);
  943.   }
  944.   else if (Chinese == TRUE && multichar (* * poipoi)) {
  945.     (* poipoi) ++;
  946.     (* poipoi) ++;
  947.     (* colpoi) ++;
  948.     (* colpoi) ++;
  949.   }
  950.   else {
  951.     (* poipoi) ++;
  952.     (* colpoi) ++;
  953.   }
  954. }
  955.  
  956. /*
  957.  * JUS justifies the current line according to the current margins
  958.  */
  959. void
  960. JUS ()
  961. {
  962.   char * poi;
  963.   char * last_blank;
  964.   int column;
  965.  
  966.   poi = cur_line->text;
  967.   column = 0;
  968.   while (column < left_margin && (poi < cur_text || white_space (* poi))) {
  969.     advance_char (& poi, & column);
  970.   }
  971.   if (column < left_margin) {
  972.     move_address (poi, y);
  973.     while (column < left_margin) {
  974.         if (tab (column) <= left_margin) {
  975.             S ('\t');
  976.             column = tab (column);
  977.         } else {
  978.             S (' ');
  979.             column ++;
  980.         }
  981.     }
  982.     poi = cur_line->text;    /* old text pointer may be invalid */
  983.     column = 0;        /* so start again */
  984.   }
  985.   last_blank = NIL_PTR;
  986.   while (column < right_margin && * poi != '\n') {
  987.     if (column >= left_margin &&
  988.         (white_space (* poi) || * poi == '-')) last_blank = poi;
  989.     advance_char (& poi, & column);
  990.   }
  991.   if (* poi != '\n') {
  992.     if (last_blank != NIL_PTR) {
  993.         poi = last_blank;
  994.         poi ++;
  995.         move_address (poi, y);
  996.         SNL ();
  997.         JUS ();
  998.     }
  999.     else {    /* no wrapping point found */
  1000.         while (! white_space (* poi) && * poi != '\n')
  1001.             advance_char (& poi, & column);    /* to handle Chin. */
  1002.         if (* poi == '\n') {
  1003.             move_address (poi, y);
  1004.             MRT ();
  1005.         }
  1006.         else {
  1007.             poi ++;
  1008.             move_address (poi, y);
  1009.             if (* poi != '\n') SNL ();
  1010.             else MRT ();
  1011.             JUS ();
  1012.         }
  1013.     }
  1014.   }
  1015.   else if (poi - last_blank == 1) {
  1016.     move_address (poi, y);
  1017.     DCC ();
  1018.     while (white_space (* cur_text)) DCC ();
  1019.     if (* cur_text != '\n') JUS ();
  1020.     else {
  1021.         poi = cur_text;
  1022.         poi --;
  1023.         if (Chinese == TRUE && inmultichar (cur_line->text, poi))
  1024.             poi --;
  1025.         while (white_space (* poi)) {
  1026.             DPC ();
  1027.             poi = cur_text;
  1028.             poi --;
  1029.             if (Chinese == TRUE && inmultichar (cur_line->text, poi))
  1030.                 poi --;
  1031.         }
  1032.         MRT ();
  1033.     }
  1034.   }
  1035.   else {
  1036.     move_address (poi, y);
  1037.     MRT ();
  1038.   }
  1039. }
  1040.  
  1041. void
  1042. modify_int (name, var, min, max)
  1043.   char * name;
  1044.   int * var;
  1045.   int min, max;
  1046. {
  1047.   int number;
  1048.  
  1049.   build_string (text_buffer, "%s (%d), new value (Enter for current column):", name, * var);
  1050.   if (get_number (text_buffer, '0', & number) == ERRORS) return;
  1051.   if (number == 0) number = x + 1;
  1052.   if (number < min) {
  1053.     error ("Value too small", NIL_PTR);
  1054.     return;
  1055.   }
  1056.   if (number > max) {
  1057.     error ("Value too large", NIL_PTR);
  1058.     return;
  1059.   }
  1060.   * var = number;
  1061. }
  1062.  
  1063. void
  1064. ADJLM ()
  1065. {    left_margin ++;
  1066.     modify_int ("left margin", & left_margin, 1, right_margin - 2);
  1067.     left_margin --;
  1068. }
  1069.  
  1070. void
  1071. ADJRM ()
  1072. {    right_margin --;
  1073.     modify_int ("right margin", & right_margin, left_margin + 2, 1000);
  1074.     right_margin ++;
  1075. }
  1076.  
  1077. /*  ==================================================================    *
  1078.  *                Miscellaneous                *
  1079.  *  ==================================================================    */
  1080.  
  1081. /*
  1082.  * Redraw the screen
  1083.  */
  1084. void
  1085. RD ()
  1086. {
  1087.   reverse_off ();
  1088.   clear_screen ();
  1089.  
  1090. /* display page */
  1091.   display (0, top_line, last_y, y);
  1092.  
  1093. /* clear/redraw last line */
  1094.   set_cursor (0, YMAX);
  1095.   clear_lastline ();
  1096.   move_y (y);
  1097.   if (stat_visible == TRUE) rd_bottom_line ();
  1098. }
  1099.  
  1100. void
  1101. RD_y (y_pos)
  1102.   int y_pos;
  1103. {
  1104.   reverse_off ();
  1105.   clear_screen ();
  1106.  
  1107. /* display page */
  1108.   display (0, top_line, last_y, y_pos);
  1109.  
  1110. /* clear/redraw last line */
  1111.   set_cursor (0, YMAX);
  1112.   clear_lastline ();
  1113.   if (stat_visible == TRUE) rd_bottom_line ();
  1114. }
  1115.  
  1116. /*
  1117.  * Adjust current window size after WINCH signal
  1118.  */
  1119. void
  1120. RDwin ()
  1121. {
  1122.   register LINE * current_line;
  1123.  
  1124.   winchg = FALSE;
  1125.   getwinsize ();
  1126.  
  1127.   current_line = cur_line;
  1128.   reset (top_line, y);
  1129. /*  move_y (find_y_w_o_RD (current_line)); */
  1130.   move_address (cur_text, find_y_w_o_RD (current_line));
  1131.   RD ();
  1132.   flush ();
  1133. }
  1134.  
  1135. void
  1136. change_screen_size (sb, keep_columns)
  1137.   FLAG sb, keep_columns;
  1138. {
  1139.   int index, mode1, mode2;
  1140.  
  1141. /* Experimental area: */
  1142. /*    set_screen_mode (mode1);    any available mode number */
  1143. /*    set_video_lines (mode1);    0/1/2: 200/350/400 lines */
  1144.     /* does not seem to have any effect */
  1145. /*    set_textmode_height (mode1);    0/1/2: font height 8/14/16 */
  1146. /*    set_grafmode_height (mode1, mode2);
  1147.         0/1/2: font height 8/14/16 1/2/3/n: 14/25/43/n lines */
  1148. /*    set_fontbank (f);        0..7 */
  1149. /**/
  1150.   if (hop_flag > 0) {
  1151. #ifdef msdos
  1152.     if (keep_columns == TRUE) {
  1153.       if (sb == BIGGER) {
  1154.     index = get_number ("Switch to font bank (0..7) ", '\0', & mode1);
  1155.     if (index == ERRORS) return;
  1156.     set_fontbank (mode1);
  1157.       } else {
  1158.     index = get_number ("Set character height (<= 32 pixels) ", '\0', & mode1);
  1159.     if (index == ERRORS) return;
  1160.     set_font_height (mode1);
  1161.       }
  1162.     } else {
  1163.       if (sb == BIGGER) {
  1164. #endif
  1165.     index = get_number ("Select video mode ", '\0', & mode1);
  1166.     if (index == ERRORS) return;
  1167.     set_screen_mode (mode1);
  1168. #ifdef msdos
  1169.       } else {
  1170.     index = get_number ("Select graf font (0/1/2: font height 8/14/16) ", '\0', & mode1);
  1171.     if (index == ERRORS) return;
  1172.     index = get_number ("Select line number (1/2/3/n: 14/25/43/n) ", '\0', & mode2);
  1173.     if (index == ERRORS) return;
  1174.     set_grafmode_height (mode1, mode2);    /* 0/1/2: font height 8/14/16 */
  1175.                     /* 1/2/3/n: 14/25/43/n lines */
  1176.       }
  1177.     }
  1178. #endif
  1179.   } else
  1180.   {
  1181.     resize_screen (sb, keep_columns);
  1182.   }
  1183.   RDwin ();
  1184. }
  1185.  
  1186. void
  1187. LNCI ()
  1188. {
  1189.   switch_textmode_height (TRUE);
  1190.   RDwin ();
  1191. }
  1192.  
  1193. void
  1194. LNSW ()
  1195. {
  1196.   switch_textmode_height (FALSE);
  1197.   RDwin ();
  1198. }
  1199.  
  1200. /*
  1201.  * Ignore this keystroke.
  1202.  */
  1203. void
  1204. I ()
  1205. {
  1206. }
  1207.  
  1208. /*
  1209.  * Fortifying 'HOP' key.
  1210.  */
  1211. void
  1212. HOP ()
  1213. {
  1214.   hop_flag = 2;
  1215.   if (! char_ready_within (500))
  1216.     status_msg ("Continue HOP command (next command fortified) ...");
  1217. }
  1218.  
  1219. /*
  1220.  * Cancel prefix function.
  1221.  */
  1222. void
  1223. CANCEL ()
  1224. {
  1225.   hop_flag = 0;
  1226.   clear_status ();
  1227. }
  1228.  
  1229. /*
  1230.  * Call proc associated with function key.
  1231.  */
  1232. void
  1233. FUNKEY ()
  1234. {
  1235.   (* keyproc) ('\0');
  1236.   keyproc = I;
  1237. }
  1238.  
  1239. /*
  1240.  * Toggle insert/overwrite mode.
  1241.  */
  1242. void
  1243. TOGINS ()
  1244. {
  1245.   if (insert_mode == TRUE) insert_mode = FALSE;
  1246.   else insert_mode = TRUE;
  1247. }
  1248.  
  1249. #define cmd_char(c)    (c < '\040' ? c + '\100' : (c >= '\140' ? c - '\040' : c))
  1250.  
  1251. /*
  1252.  * Interpret control-Q commands. Most can be implemented with the Hop function.
  1253.  */
  1254. void
  1255. ctrlQ ()
  1256. {
  1257.   uchar c;
  1258.   void (* func) ();
  1259.  
  1260.   if (! char_ready_within (500))
  1261.     status_msg ("^Q: Save Done eXit Quit Read Log / block: B/K mark Cop Ydel moV Wr...");
  1262.   if (quit == TRUE) return;
  1263.   c = readchar ();
  1264.   if (quit == TRUE) return;
  1265.   clear_status ();
  1266.   if ('0' <= c && c <= '9') {GOMAn (c); return;}
  1267.   if (c == '\033' || c == QUITCHAR) {CANCEL (); return;}
  1268.   switch (cmd_char (c)) {
  1269.     case 'B' : {GOMA () ; return;}
  1270.     case 'K' : { ; return;}        /* not exactly WS function */
  1271.     case 'P' : { ; return;}        /* not exactly WS function */
  1272.     case 'V' : { ; return;}        /* not exactly WS function */
  1273.     case 'W' :            /* not exactly WS function */
  1274.     case 'Z' :            /* not exactly WS function */
  1275.     case 'Y' :
  1276.     case '\177' : {
  1277.             func = key_map [c];
  1278.             hop_flag = 1;
  1279.             (* func) (c);
  1280.             return;
  1281.               }
  1282.     case 'F' : {if (hop_flag > 0)
  1283.             SRV ();
  1284.             else
  1285.             SFW ();
  1286.             return;
  1287.            }
  1288.     case 'A' : {if (hop_flag > 0)
  1289.             REPL ();
  1290.             else
  1291.             GR ();
  1292.             return;
  1293.            }
  1294.     case 'Q' : {REPT (' '); return;}    /* not exactly WS function */
  1295.     case 'L' :            /* not exactly WS function */
  1296. /*
  1297. ^Q: B/K top/bottom block
  1298.     P last position
  1299.     W/Z continuous scroll
  1300.     V last find or block
  1301.     Y/DEL delete line right/left
  1302.     0-9 marker
  1303.     F find
  1304.     A replace
  1305.     Q repeat next key/command
  1306.     L find misspelling
  1307. */
  1308.     default : {
  1309.            func = key_map [c];
  1310.            if ((c < ' ') || ((voidfunc) func == (voidfunc) FUNKEY)) {
  1311.     /* (voidfunc) is an identity cast here. It seems to be required for
  1312.        the sake of the apparently totally rotten microvax C compiler */
  1313.             hop_flag = 1;
  1314.             (* func) (c);
  1315.            }
  1316.            else
  1317.             BAD (c);
  1318.            return;
  1319.           }
  1320.   }
  1321. }
  1322.  
  1323. /*
  1324.  * Interpret control-K commands.
  1325.  */
  1326. void
  1327. ctrlK ()
  1328. {
  1329.   uchar c;
  1330.  
  1331.   if (! char_ready_within (500))
  1332.     status_msg ("^K: Save Done eXit Quit Read Log / block: B/K mark Cop Ydel moV Wr...");
  1333.   if (quit == TRUE) return;
  1334.   c = readchar ();
  1335.   if (quit == TRUE) return;
  1336.   clear_status ();
  1337.   if ('0' <= c && c <= '9') {MARKn (c); return;}
  1338.   if (c == '\033' || c == QUITCHAR) {CANCEL (); return;}
  1339.   switch (cmd_char (c)) {
  1340.     case 'S' : {WTU (); return;}
  1341.     case 'D' : {EXFILE (); return;}
  1342.     case 'X' : {EXMINED (); return;}
  1343.     case 'Q' : {QUED (); return;}
  1344.     case 'B' : {MARK () ; return;}
  1345.     case 'K' : {YA () ; return;}    /* not exactly WS function */
  1346.     case 'H' : { ; return;}        /* not exactly WS function */
  1347.     case 'C' : {PT () ; return;}    /* not exactly WS function */
  1348.     case 'Y' : {DT () ; return;}    /* not exactly WS function */
  1349.     case 'V' : {PT (); return;}    /* not exactly WS function */
  1350.     case 'W' : {WB (); return;}    /* not exactly WS function */
  1351.     case 'N' : { ; return;}        /* not exactly WS function */
  1352.     case 'R' : {INSFILE (); return;}
  1353.     case 'L' : {CHDI (); return;}
  1354. /*
  1355. ^K  0-9 set/hide marker
  1356.     B/K block begin/end
  1357.     H block hide
  1358.     C/Y/V/W block copy/delete/move/write
  1359.     N column block
  1360. */
  1361.     default : {
  1362.            BAD (c);
  1363.            return;
  1364.           }
  1365.   }
  1366. }
  1367.  
  1368. /*
  1369.  * Interpret control-O commands.
  1370.  */
  1371. void
  1372. ctrlO ()
  1373. {
  1374.   uchar c;
  1375.  
  1376.   if (! char_ready_within (500))
  1377.     status_msg ("^O: L/R left/right margins...");
  1378.   if (quit == TRUE) return;
  1379.   c = readchar ();
  1380.   if (quit == TRUE) return;
  1381.   clear_status ();
  1382.   if ('0' <= c && c <= '9') {return;}
  1383.   if (c == '\033' || c == QUITCHAR) {CANCEL (); return;}
  1384.   switch (cmd_char (c)) {
  1385.     case 'L' : {ADJLM (); return;}
  1386.     case 'R' : {ADJRM (); return;}
  1387. /*
  1388. ^O  L/R/M set left/right margin /release
  1389.     I/N set/clear tab
  1390.     G paragraph tab
  1391.     F ruler from line
  1392.     C center line
  1393.     S set line spacing
  1394.     W toggle word wrap
  1395.     T toggle ruler line
  1396.     J toggle justify
  1397.     V     vari-tabs
  1398.     H     hyph-help
  1399.     E     soft hyph
  1400.     D     print display
  1401.     P     page break
  1402. */
  1403.     default : {
  1404.            BAD (c);
  1405.            return;
  1406.           }
  1407.   }
  1408. }
  1409.  
  1410. /*
  1411.  * Interpret Escape commands.
  1412.  */
  1413. void
  1414. ESCAPE ()
  1415. {
  1416.   uchar c;
  1417.   void (* func) ();
  1418.  
  1419.   if (! char_ready_within (500))
  1420.     status_msg ("ESC(exit) q(uit w(rite e(dit /\\(search) r(eplace d(irectory h(elp ...");
  1421.   if (quit == TRUE) return;
  1422.   c = readchar ();
  1423.   if (quit == TRUE) return;
  1424.   clear_status ();
  1425.   if ('0' <= c && c <= '9') {REPT (c); return;}
  1426.   switch (c) {
  1427.     case '\033' : {EXED (); return;}
  1428.     case 'q' : {QUED (); return;}
  1429.     case '/' : {SFW (); return;}
  1430.     case '\\' : {SRV (); return;}
  1431.     case 's' : {GR (); return;}
  1432.     case 'R' : {LR (); return;}
  1433.     case 'r' : {REPL (); return;}
  1434.     case 'w' : {WT (); return;}
  1435.     case 'W' : {WTU (); return;}
  1436.     case 'e' : {EDIT (); return;}
  1437.     case 'v' : {VIEW (); return;}
  1438.     case 'g' : {GOTO (); return;}
  1439.     case 'h' : {HELP (); return;}
  1440.     case '?' : {FS (); return;}
  1441.     case '.' : {RDwin (); return;}
  1442.     case 'i' : {INSFILE (); return;}
  1443.     case 'b' : {WB (); return;}
  1444.     case '=' : {REPT (' '); return;}
  1445.     case 'z' : {SUSP (); return;}
  1446.     case 'd' : {CHDI (); return;}
  1447.     case '!' : {SH (); return;}
  1448.     case ']' : {GOMA (); return;}
  1449.     case 'n' : {NN (); return;}
  1450.     case 'p' : {PBUF (); return;}
  1451.     case 'c' : {CMD (); return;}
  1452.     case ' ' : return;
  1453.     case 'X' : {changetocode (16); return;}
  1454.     case 'O' : {changetocode (8); return;}
  1455.     case 'D' : {changetocode (10); return;}
  1456.     case '+' : {NXTFILE (); return;}
  1457.     case '-' : {PRVFILE (); return;}
  1458.     case '#' : {NTHFILE (); return;}
  1459. #ifdef msdos
  1460.     case 'm' : {change_screen_size (SMALLER, FALSE); return;}
  1461.     case 'M' : {change_screen_size (BIGGER, FALSE); return;}
  1462.     case 'l' : {change_screen_size (SMALLER, TRUE); return;}
  1463.     case 'L' : {change_screen_size (BIGGER, TRUE); return;}
  1464. #endif
  1465.     case 'j' : {JUS (); return;}
  1466.     case '<' : {ADJLM (); return;}
  1467.     case '>' : {ADJRM (); return;}
  1468.     case QUITCHAR : {CANCEL (); return;}
  1469.     default : {
  1470.            func = key_map [c];
  1471.            if ((c < ' ') || ((voidfunc) func == (voidfunc) FUNKEY)) {
  1472.     /* (voidfunc) is an identity cast here. It seems to be required for
  1473.        the sake of the apparently totally rotten microvax C compiler */
  1474.             hop_flag = 1;
  1475.             (* func) (c);
  1476.            }
  1477.            else
  1478.             BAD (c);
  1479.            return;
  1480.           }
  1481.   }
  1482. }
  1483.  
  1484. /*
  1485.  * DIRECT () reads in a direct cursor movement input sequence and moves.
  1486.  */
  1487. void
  1488. DIRECT ()
  1489. {
  1490.   uchar c;
  1491.   int xpos, ypos;
  1492.  
  1493.   c = get_digits (& ypos); /* c should be ';' */
  1494.   c = get_digits (& xpos);
  1495.   ypos = ypos - 1;
  1496.   xpos = xpos - 1;
  1497.   if (ypos > last_y) ypos = last_y;
  1498.   move_to (xpos, ypos);
  1499.   if (c == 'm') MARK (); /* middle mouse button */
  1500.   if (c == 'r') YA (); /* right mouse button */
  1501. }
  1502.  
  1503. /*
  1504.  * REPT () prompts for a count and wants a command after that. It repeats the
  1505.  * command count times. If a ^\ is given during repeating, stop looping and
  1506.  * return to main loop.
  1507.  */
  1508. void
  1509. REPT (firstdigit)
  1510.   char firstdigit;
  1511. {
  1512.   register int count;
  1513.   register void (* func) ();
  1514.   int index, number;
  1515.  
  1516.   hop_flag = 0;
  1517.   if (firstdigit >= '0' && firstdigit <= '9')
  1518.      index = get_number ("Please continue repeat count...", firstdigit, & number);
  1519.   else
  1520.      index = get_number ("Please enter repeat count...", '\0', & number);
  1521.   if (index == ERRORS) return;
  1522.  
  1523.   func = key_map [index];
  1524.   if ((voidfunc) func == (voidfunc) I) {    /* Function assigned? */
  1525.     /* (voidfunc) is an identity cast here. It seems to be required for
  1526.        the sake of the apparently totally rotten microvax C compiler */
  1527.     clear_status ();
  1528.     return;
  1529.   }
  1530.   if ((voidfunc) func == (voidfunc) FUNKEY) {
  1531.     /* (voidfunc) is an identity cast here. It seems to be required for
  1532.        the sake of the apparently totally rotten microvax C compiler */
  1533.     func = * keyproc;
  1534.     keyproc = I;
  1535.     index = '\0';
  1536.   }
  1537.  
  1538.   count = number;
  1539.   while (count -- > 0 && quit == FALSE) {
  1540.     if (stat_visible == TRUE)
  1541.         clear_status ();
  1542.     (* func) (index);
  1543.     flush ();
  1544.   }
  1545.  
  1546.   if (quit == TRUE)        /* Abort has been given */
  1547.     error ("Repeat aborted", NIL_PTR);
  1548.   else
  1549.     clear_status ();
  1550. }
  1551.  
  1552. /*
  1553.  * Complains to illegal commands and eats up illegal escape sequences.
  1554.  */
  1555. void
  1556. BAD (c)
  1557.   uchar c;
  1558. {
  1559.   static char message2 [] = "'**' - type a blank";
  1560.  
  1561.   if (c < ' ')    { message2 [1] = '^'; message2 [2] = c + '@'; }
  1562.   else        { message2 [1] = ' '; message2 [2] = c; }
  1563.   error ("Unknown command ", message2);
  1564.   while (readchar () != ' ' && quit == FALSE) {
  1565.     ring_bell ();
  1566.     flush ();
  1567.   }
  1568.   clear_status ();
  1569. }
  1570.  
  1571. /*
  1572.  * Change working directory.
  1573.  */
  1574. void
  1575. CHDI ()
  1576. {
  1577.   char new_dir [maxLINE_LEN];    /* Buffer to hold new dir. name */
  1578.  
  1579. #ifdef pc
  1580.   build_string (text_buffer, "Drive/Directory: %s, change to:", unnull (getcwd (new_dir, maxLINE_LEN)));
  1581. #else
  1582.   build_string (text_buffer, "Directory: %s, change to:", unnull (getcwd (new_dir, maxLINE_LEN)));
  1583. #endif
  1584.  
  1585.   if (get_file (text_buffer, new_dir) != FINE)
  1586.     return;
  1587. #ifdef msdos
  1588.   if (new_dir [0] != '\0' && new_dir [1] == ':')
  1589.     if (new_dir [2] == '\0') {
  1590.         new_dir [2] = '.';    /* change to current dir. of drive */
  1591.         new_dir [3] = '\0';
  1592.     }
  1593. #endif
  1594.   if (chdir (new_dir) == 0) {
  1595. #ifdef msdos
  1596.     if (new_dir [0] != '\0' && new_dir [1] == ':')
  1597.         setdisk (((int) new_dir [0] & (int) '\137') - (int) 'A');
  1598.     RD ();    /* disk error dialog may be on screen after chdir */
  1599. #endif
  1600.     clear_status ();
  1601.     overwriteOK = FALSE;    /* Same file base name ... */
  1602.     writable = TRUE;
  1603. /*    if (viewmode == FALSE)    */
  1604.         modified = TRUE;    /* would mean different file now */
  1605.   }
  1606.   else    {
  1607. #ifdef msdos
  1608.     RD ();    /* disk error dialog may be on screen */
  1609. #endif
  1610.     error ("Could not change work dir: ", serror ());
  1611.   }
  1612. }
  1613.  
  1614. /*
  1615.  * Print file status.
  1616.  */
  1617. void
  1618. FS1 ()
  1619. {
  1620.   fstatus (file_name [0] ? "" : "[buffer]", -1L);
  1621. }
  1622. void
  1623. FS ()
  1624. {
  1625.   if (hop_flag > 0)    if (fstat_always == FALSE) fstat_always = TRUE;
  1626.             else fstat_always = FALSE;
  1627.   else FS1 ();
  1628. }
  1629.  
  1630. /*
  1631.  * Show Help information on screen
  1632.  */
  1633. void
  1634. HELP ()
  1635. {
  1636.   if (getenv ("MINEDHELP"))
  1637.     build_string (text_buffer, (char *) getenv ("MINEDHELP"), mined_dir);
  1638.   else    build_string (text_buffer, helpcommand, mined_dir);
  1639.   clear_screen ();
  1640.   status_msg ("Wait for help...");
  1641.   flush ();
  1642.   raw_mode (OFF);
  1643.   system (text_buffer);
  1644.   sleep (1);
  1645.   raw_mode (ON);
  1646. #ifdef pc
  1647.   status_msg ("help finished, press a key...");
  1648.   flush ();
  1649.   (void) readchar ();
  1650. #endif
  1651.   clear_status ();
  1652.   RDwin ();
  1653. }
  1654.  
  1655. /*
  1656.  * Print buffer
  1657.  */
  1658. void
  1659. PBUF ()
  1660. {
  1661.   int fd;
  1662.   char cmd [maxLINE_LEN];    /* Buffer for print command */
  1663.  
  1664.   if ((fd = scratch_file (READ, FALSE)) == ERRORS) {
  1665.     error ("Buffer is empty.", NIL_PTR);
  1666.     return;
  1667.   }
  1668.   close (fd);
  1669.   build_string (cmd, getenv ("MINEDPRINT") ?
  1670.         (char *) getenv ("MINEDPRINT") : printcommand, yank_file);
  1671. /* Turbo-C wants the cast here since getenv must be declared as far * */
  1672.   clear_status ();
  1673.   set_cursor (0, YMAX);
  1674.   flush ();
  1675.   system (cmd);
  1676.   sleep (1);
  1677.   RDwin ();
  1678. }
  1679.  
  1680. /*
  1681.  * Pipe buffer
  1682.  */
  1683. void
  1684. CMD ()
  1685. {
  1686.   int fd;
  1687.   char cmd [maxLINE_LEN];    /* Buffer for command */
  1688.   char command [maxLINE_LEN];    /* Buffer for full command */
  1689.  
  1690.   if ((fd = scratch_file (READ, FALSE)) == ERRORS) {
  1691.     error ("Buffer is empty.", NIL_PTR);
  1692.     return;
  1693.   }
  1694.   close (fd);
  1695.   if (get_string ("Command with buffer as input:", cmd, TRUE) != FINE)
  1696.     return;
  1697.   build_string (command, "%s < %s", cmd, yank_file);
  1698.   clear_status ();
  1699.   set_cursor (0, YMAX);
  1700.   flush ();
  1701.   raw_mode (OFF);
  1702.   system (command);
  1703.   sleep (1);
  1704.   raw_mode (ON);
  1705.   RDwin ();
  1706. }
  1707.  
  1708. /*
  1709.  * Called if an operation is not implemented
  1710.  */
  1711. void
  1712. notimpl ()
  1713. {
  1714.   error ("Command not implemented", NIL_PTR);
  1715. }
  1716.  
  1717. /*
  1718.  * Suspend editor after writing back the file.
  1719.  */
  1720. void
  1721. SUSP ()
  1722. {
  1723.   if (cansuspendmyself == TRUE) {
  1724.     if (hop_flag == 0 && modified == TRUE)
  1725.         if (wrt_text (TRUE) == ERRORS) return;
  1726.     set_cursor (0, YMAX);
  1727.     raw_mode (OFF);
  1728.     suspendmyself ();
  1729.     raw_mode (ON);
  1730.     clear_status ();
  1731.     RDwin ();
  1732.   }
  1733.   else notimpl ();
  1734. }
  1735.  
  1736. /*
  1737.  * Call an interactive shell.
  1738.  */
  1739. void
  1740. SH ()
  1741. {
  1742. #ifdef unix
  1743.   register int w;
  1744.   int pid, status, waiterr;
  1745.  
  1746.   switch (pid = vfork ()) {
  1747.     case -1:            /* Error */
  1748.         error ("Cannot fork: ", serror ());
  1749.         return;
  1750.     case 0:                /* This is the child */
  1751.         set_cursor (0, YMAX);
  1752.         putchar ('\n');
  1753.         raw_mode (OFF);
  1754.         if (rpipe) {            /* Fix stdin */
  1755.             close (STD_IN);
  1756.             if (open ("/dev/tty", O_RDONLY, 0) < 0)
  1757.                   exit (126);
  1758.         }
  1759.         execl (getenv ("SHELL"), getenv ("SHELL"), 0);
  1760.         _exit (127);    /* Exit with 127 */
  1761.     default:            /* This is the parent */
  1762.         do {
  1763.             w = wait (& status);
  1764.         } while (w != -1 && w != pid);
  1765.         waiterr = geterrno ();
  1766.   }
  1767.  
  1768.   raw_mode (ON);
  1769.   RDwin ();
  1770.  
  1771.   if (w == -1) {
  1772.     error ("Wait error: ", serrorof (waiterr));
  1773.     if (((status >> 8) == 127) || ((status >> 8) == 126)) sleep (2);
  1774.   }
  1775.   if ((status >> 8) == 127)        /* Child died with 127 */
  1776.     error (getenv ("SHELL"), ": cannot exec this ${SHELL} (not found / not enough memory ?)");
  1777.   else if ((status >> 8) == 126)
  1778.     error ("Cannot open /dev/tty as fd #0", NIL_PTR);
  1779. #else
  1780. # ifdef msdos
  1781.   char old_dir [maxLINE_LEN];    /* Buffer to hold dir. name */
  1782.  
  1783.   (void) getcwd (old_dir, maxLINE_LEN);
  1784.  
  1785.   set_cursor (0, YMAX);
  1786.   raw_mode (OFF);
  1787.   system ("COMMAND.COM");
  1788.   raw_mode (ON);
  1789.   clear_status ();
  1790.   RDwin ();
  1791.  
  1792.   if (chdir (old_dir) == 0) {
  1793.     if (old_dir [0] != '\0' && old_dir [1] == ':')
  1794.         setdisk (((int) old_dir [0] & (int) '\137') - (int) 'A');
  1795.     RD ();    /* disk error dialog may be on screen after chdir */
  1796.   } else {
  1797.     overwriteOK = FALSE;    /* Same file base name ... */
  1798.     writable = TRUE;
  1799. /*    if (viewmode == FALSE)    */
  1800.         modified = TRUE;    /* would mean different file now */
  1801.     RD ();    /* disk error dialog may be on screen */
  1802.     error ("Could not reset previous work dir: ", serror ());
  1803.   }
  1804.  
  1805. # else
  1806. #  ifdef vms
  1807. /* Who can tell me why this hangs the process after return from the CLI ?
  1808.   set_cursor (0, YMAX);
  1809.   raw_mode (OFF);
  1810.   system ("SPAWN");
  1811.   raw_mode (ON);
  1812.   clear_status ();
  1813.   RDwin ();
  1814. */
  1815.   notimpl ();
  1816. #  else
  1817.   notimpl ();
  1818. #  endif
  1819. # endif
  1820. #endif
  1821. }
  1822.  
  1823. /*  ==================================================================    *
  1824.  *                Main                    *
  1825.  *  ==================================================================    */
  1826.  
  1827. char * minedopt;
  1828.  
  1829. void
  1830. WordStar_keys ()
  1831. {
  1832.   int i;
  1833.  
  1834.   for (i = 0; i < 32; i ++) key_map [i] = ws_key_map [i];
  1835.   control_prefix = '\020';
  1836. }
  1837.  
  1838. FLAG
  1839. eval_option ()
  1840. {
  1841.   switch (* minedopt) {
  1842.     case 'v': viewonly = TRUE; break;
  1843.     case 'm': multiexit = TRUE; break;
  1844.     case 'p': proportional = TRUE; break;
  1845.     case 'r': RET_opt = 'r'; break;
  1846.     case 'R': RET_opt = 'R'; break;
  1847.     case 'C': Chinese = TRUE; break;
  1848.     case 'B': key_map ['\010'] = DPC;
  1849.           key_map ['\177'] = DCC;
  1850.           break;
  1851.     case 'W': WordStar_keys (); break;
  1852.     case 's': page_stay = TRUE; break;
  1853.     case 'S': page_scroll = TRUE; break;
  1854.     case 't': minedopt ++;
  1855.           if (* minedopt == '\0') {minedopt --; TABchar = TABdefault;}
  1856.           else TABchar = * minedopt;
  1857.           break;
  1858.     case 'd': minedopt ++;
  1859.           if (* minedopt == '-') display_delay = -1;
  1860.           else if (* minedopt >= '0' && * minedopt <= '9')
  1861.             display_delay = (int) * minedopt - (int) '0';
  1862.           else minedopt --;
  1863.           break;
  1864.     default:  return FALSE;
  1865.   }
  1866.   return TRUE;
  1867. }
  1868.  
  1869. int
  1870. main (argc, argv)
  1871.   int argc;
  1872.   char * argv [];
  1873. {
  1874.   register int index;    /* index in key table */
  1875.   int initlinenum;
  1876.   int initlini = 0;
  1877.   LINE * initline;
  1878.   char * Mark;
  1879.   FLAG goon;
  1880.  
  1881. /* fprot = umask (0); */
  1882.  
  1883.   build_string (mined_dir, argv [0]);
  1884.   index = 0;
  1885.   while (mined_dir [index] != '\0') index ++;
  1886.   while (index >= 0 && mined_dir [index] != '/'
  1887. #ifdef msdos
  1888.         && mined_dir [index] != '\\' && mined_dir [index] != ':'
  1889. #endif
  1890. #ifdef vms
  1891.         && mined_dir [index] != ']' && mined_dir [index] != ':'
  1892. #endif
  1893.     ) index --;
  1894.   index ++; mined_dir [index] = '\0';
  1895.  
  1896.   if (getenv ("NoCtrlSQ") || getenv ("NoControlSQ")) {
  1897.     /* ^S and ^Q may come arbitrarily from terminal, so don't use them */
  1898.     controlQS = TRUE;
  1899.     key_map ['\021'] = I;
  1900.     key_map ['\023'] = I;
  1901.   }
  1902. /*  if (getenv ("MINEDMULT")) multiexit = TRUE; */
  1903.   if (getenv ("MINEDPROP")) proportional = TRUE;
  1904.   if (getenv ("MINEDCHIN")) Chinese = TRUE;
  1905.   if (getenv ("MINEDMAC")) RET_opt = 'R';
  1906.   if (getenv ("MINEDWS")) WordStar_keys ();
  1907.   Mark = (char *) getenv ("MINEDSHIFT");
  1908. /* Turbo-C wants the cast here since getenv must be declared as far * */
  1909.   if (Mark != NIL_PTR) {
  1910.     SHIFT_MARK = Mark [0];
  1911.     if (Mark [0] != '\0') SHIFT_BEG = Mark [1];
  1912.   }
  1913.   Mark = (char *) getenv ("MINEDTAB");
  1914.   if (Mark != NIL_PTR) TABchar = (Mark [0] == '\0' ? TABdefault : Mark [0]);
  1915.   Mark = (char *) getenv ("MINEDRET");
  1916.   if (Mark != NIL_PTR) {
  1917.     RET_MARK = Mark [0];
  1918.     if (RET_MARK) RET_BLANK = Mark [1];
  1919.     if (RET_BLANK) RET_BLANK2 = Mark [2];
  1920.   }
  1921.  
  1922.   get_term ();
  1923.  
  1924.   if ((minedopt = (char *) getenv ("MINED")) != NIL_PTR)
  1925.      while (* minedopt != '\0') {
  1926.     (void) eval_option ();
  1927.     minedopt ++;
  1928.   }
  1929.  
  1930.   fnami = 1;
  1931.   goon = TRUE;
  1932.   do {
  1933.     if (fnami < argc) {
  1934.       if (* argv [fnami] == '+') {
  1935.     initlini = fnami;
  1936.     fnami += 1;
  1937.       }
  1938.       else if (* argv [fnami] == '-'
  1939. #ifdef msdos
  1940.           || * argv [fnami] == '/'
  1941. #endif
  1942.           ) {
  1943.     minedopt = argv [fnami];
  1944.     minedopt ++;
  1945.     goon = eval_option ();
  1946.     fnami += 1;
  1947.       }
  1948.       else goon = FALSE;
  1949.     } else goon = FALSE;
  1950.   } while (goon == TRUE);
  1951.  
  1952.   fnami_min = fnami;
  1953.   fnami_max = argc - 1;
  1954.   fnami_cnt = argc - fnami_min;
  1955.   fnamv = argv;    /* Why did this produce a warning? C is such a stupid language! */
  1956.   if (! (fnami < argc))
  1957.      fnami = 0;
  1958.  
  1959.   if (! isatty (STD_IN)) {    /* Reading from pipe */
  1960.     if (fnami != 0) {
  1961.         panic ("Cannot read both pipe and file", NIL_PTR);
  1962.     }
  1963.     rpipe = TRUE;
  1964.     modified = TRUE;    /* Set modified flag not to loose buffer */
  1965. #ifdef msdos
  1966.     panic ("Cannot edit after input from pipe", "MSDOS C incompatibility");
  1967. #else
  1968.     if ((input_fd = open ("/dev/tty", O_RDONLY, 0)) < 0)
  1969.        panic ("Cannot open /dev/tty for read", serror ());
  1970. #endif
  1971.   }
  1972.   if (! isatty (STD_OUT)) {
  1973.     wpipe = TRUE;
  1974.     modified = TRUE; /* Set modified flag not to ignore buffer on exit */
  1975.     /*    if ((output_fd = open ("/dev/tty", O_WRONLY, 0)) < 0)
  1976.        panic ("Cannot open /dev/tty for write", serror ()); */
  1977.   }
  1978.  
  1979.   raw_mode (ON);    /* Set tty to appropriate mode */
  1980.   clear_screen ();
  1981.  
  1982. /*
  1983.  * Generate names of paste files and of panic-file
  1984.  */
  1985. #ifdef unix
  1986.   temp_dir = getenv ("TMPDIR");
  1987.   if (temp_dir == NIL_PTR || temp_dir [0] == '\0') temp_dir = "/tmp";
  1988.   if (getenv ("USER")) {
  1989.     build_string (yankie_file, "%s/minedbuf.%s.", temp_dir, getenv ("USER"));
  1990.     build_string (panic_file, "%s/minedpanic.%s.%d", temp_dir, getenv ("USER"), getpid ());
  1991.   }
  1992.   else {
  1993.     build_string (yankie_file, "%s/minedbuf.%d.", temp_dir, geteuid ());
  1994.     build_string (panic_file, "%s/minedpanic.%d.%d", temp_dir, geteuid (), getpid ());
  1995.   }
  1996. #endif
  1997. #ifdef vms
  1998.   if (getenv ("SYS$SCRATCH"))
  1999.     temp_dir = "SYS$SCRATCH";
  2000.   else    temp_dir = "SYS$LOGIN";
  2001.   if (getenv ("USER")) {
  2002.     build_string (yankie_file, "%s:$MINEDBUF$%s.", temp_dir, getenv ("USER"));
  2003.     build_string (panic_file, "%s:$MINEDPANIC$%s.%d", temp_dir, getenv ("USER"), getpid ());
  2004.   }
  2005.   else {
  2006.     build_string (yankie_file, "%s:$MINEDBUF$%d.", temp_dir, geteuid ());
  2007.     build_string (panic_file, "%s:$MINEDPANIC$%d.%d", temp_dir, geteuid (), getpid ());
  2008.   }
  2009. #endif
  2010. #ifdef msdos
  2011.   temp_dir = (char *) getenv ("TEMP");
  2012.   if (temp_dir == NIL_PTR || temp_dir [0] == '\0') temp_dir = (char *) getenv ("TMP");
  2013.   if (temp_dir == NIL_PTR || temp_dir [0] == '\0') temp_dir = "\\";
  2014.   build_string (yankie_file, "%s\\minedbuf.", temp_dir);
  2015.   build_string (panic_file, "%s\\mined-pa.nic", temp_dir);
  2016. #endif
  2017.  
  2018.   header = tail = alloc_header (); /* Make header of list */
  2019.   if (header == NIL_LINE) panic ("Cannot allocate memory", NIL_PTR);
  2020.   header->text = NIL_PTR;
  2021.   header->next = tail->prev = header;
  2022.  
  2023. /* Load the file (if any) */
  2024.   if (fnami == 0)
  2025.     load_file_w_o_display (NIL_PTR);
  2026.   else {
  2027.     /* This should be applied to all file names, or better, not at all:
  2028.     if (length_of (argv [fnami]) > maxLINE_LEN) {
  2029.         argv [fnami] [maxLINE_LEN] = '\0';
  2030.     }
  2031.     */
  2032.     load_file_w_o_display (argv [fnami]);
  2033.   }
  2034.   loading = TRUE;    /* keep loading flag TRUE until entering main loop */
  2035.  
  2036.   if (initlini != 0) {
  2037.      make_number (& initlinenum, argv [initlini] + 1);
  2038.      if (initlinenum > 0) {
  2039.     if (initlinenum <= 0 || (initline = proceed (header->next, initlinenum - 1)) == tail)
  2040.        error ("Illegal line number: ", num_out ((long) initlinenum));
  2041.     else {
  2042.        move_to (x, find_y_w_o_RD (initline));
  2043.        fstatus ("Read", -1L);
  2044.     }
  2045.      }
  2046.   }
  2047.   if (wpipe) {
  2048.     file_name [0] = '\0'; /* don't let user believe he's editing a file */
  2049.     fstatus ("Editing for standard output", -1L);
  2050.   }
  2051.   RD ();
  2052.   flush ();
  2053.   catch_signals (catch_interrupt);
  2054.   loading = FALSE;
  2055.  
  2056. /* Main loop of the editor */
  2057.   for (;;) {
  2058.     if (fstat_always == TRUE && stat_visible == FALSE) FS1 ();
  2059.     index = readchar ();
  2060.     if (stat_visible == TRUE)
  2061.         clear_status ();
  2062.     if (quit == FALSE) {    /* Call the function for the typed key */
  2063.         (* key_map [index]) (index);
  2064.         if (hop_flag > 0) hop_flag --;
  2065.         flush ();    /* Flush output (if any) */
  2066.     }
  2067.     if (quit == TRUE) {
  2068.         CANCEL ();
  2069.         quit = FALSE;
  2070.     }
  2071.   }
  2072.   /* NOTREACHED */
  2073. }
  2074.  
  2075. /*  ==================================================================    *
  2076.  *                End                    *
  2077.  *  ==================================================================    */
  2078.